import functools
from threading import Lock

from loguru import logger


def singleton(class_):
    instances = {}
    lock = Lock()

    def get_instance(*args, **kwargs):
        lock.acquire()
        if class_ not in instances:
            instances[class_] = class_(*args, **kwargs)
        lock.release()
        return instances[class_]

    return get_instance


def task_done(worker):
    if worker.exception():
        logger.error(worker.result())


def task(executor):
    def wrapper(func):
        @functools.wraps(func)
        def submit(*args, **kwargs):
            f = executor.submit(func, *args, **kwargs)
            f.add_done_callback(task_done)
            return f

        func.submit = submit
        return func

    return wrapper


def synchronized(lock):
    def wrap(func):
        def synchronized_func(*args, **kwargs):
            with lock:
                return func(*args, **kwargs)

        return synchronized_func

    return wrap


def apply_sort_direction(arg_name, args, field):
    _sort_field = args.get(arg_name)
    if _sort_field and args.get('sort_dir', 'DESC') == 'DESC':
        _sort_field = f'-{_sort_field}'
    return _sort_field


def paginate(iterable, page, page_size):
    page = int(page)
    page_size = int(page_size)
    start_index = (page - 1) * page_size
    end_index = page * page_size
    return iterable[start_index: end_index]


def to_security(code, exchange_id):
    if exchange_id == '1':
        return f'{code}.XSHG'
    else:
        return f'{code}.XSHE'


def init_executor(executor):
    for i in range(executor._max_workers):
        executor.submit(lambda: None)


def del_file(path):
    try:
        path.unlink()
    except PermissionError as e:
        logger.error(e)
